/**
 * @file exercise.h
 *
 */
#ifndef EXERCISE_H
#define EXERCISE_H

#ifdef __cplusplus
extern "C" {
#endif

/*********************
*      INCLUDES
*********************/
#ifdef LV_CONF_INCLUDE_SIMPLE
#include "lvgl.h"
#include "lv_watch_conf.h"
#else
#include "../../../lvgl/lvgl.h"
#include "../../../lv_watch_conf.h"
#endif

#if USE_LV_WATCH_EXERCISE != 0

#include "lv_watch.h"

/*********************
*      DEFINES
*********************/

/**********************
*      MACROS
**********************/
#define EXERCISE_NV_PATH_PREFIX               ("C:/ui_exercise_")
#define EXERCISE_NV_PATH_SUFFIX               (".nv")
                                              
#define EXERCISE_MAX_TXT_LEN                  (50)
                                              
#define EXERCISE_MAX_ROLLER_VALUE_NUM         (6) // exclude custom
                                              
#define EXERCISE_MAX_START_UI_NUM             (6)
#define EXERCISE_MAX_ITEM_NUM_PER_START_UI    (4) // exclude time label

#define EXERCISE_GOALS_DISTANCE_HALF_MARATHON (0xfe)
#define EXERCISE_GOALS_DISTANCE_MARATHON      (0xff)

/**********************
*      TYPEDEFS
**********************/
enum {
    EXERCISE_WRITE_NV_MODE_RESET = 0,
    EXERCISE_WRITE_NV_MODE_REPLACE,
    EXERCISE_WRITE_NV_MODE_APPEND,
};
typedef uint8_t EXERCISE_WRITE_NV_MODE_T;

enum {
    EXERCISE_TYPE_NONE = 0,
    EXERCISE_TYPE_OUTDOOR_RUNNING,
    EXERCISE_TYPE_OUTDOOR_CYCLING,
    EXERCISE_TYPE_WALKING,
    EXERCISE_TYPE_FREE_TRAINING,
    EXERCISE_TYPE_MAX = EXERCISE_TYPE_FREE_TRAINING,
};
typedef uint8_t EXERCISE_TYPE_T;

typedef struct {
    uint32_t last_exercise_end_time; // in seconds
    uint32_t recovery_time; // in seconds
    uint8_t item[EXERCISE_TYPE_MAX];
} __packed exercise_nv_main_t;

typedef struct {
    EXERCISE_TYPE_T type;
    uint8_t * data;
} exercise_item_t;

typedef struct {
    lv_watch_obj_ext_t old_ext;
    lv_obj_t * list;
    lv_obj_t * recovery_time_label;
    lv_obj_t * add_btn;
    lv_ll_t items; // exercise_item_t
} exercise_ext_t;

enum {
    EXERCISE_LIST_BTN_TYPE_NORMAL = 0,
    EXERCISE_LIST_BTN_TYPE_NEXT_MENU,
    EXERCISE_LIST_BTN_TYPE_SETTING,
    EXERCISE_LIST_BTN_TYPE_SWITCH,
    EXERCISE_LIST_BTN_TYPE_CHECKBOX,
    EXERCISE_LIST_BTN_TYPE_BTN,
};
typedef uint8_t EXERCISE_LIST_BTN_TYPE_T;

typedef struct {
    void * img_src;
    lv_color_t img_bg_color;
    bool is_opacity;
    uint16_t prim_txt_id;
    char sec_txt[EXERCISE_MAX_TXT_LEN];
    EXERCISE_LIST_BTN_TYPE_T type;
    bool is_on; // valid if type is SWITCH or CHECKBOX
    lv_event_cb_t cb;
    lv_event_cb_t setting_cb;
} exercise_item_info_t;

enum {
    EXERCISE_SETTING_ITEM_TYPE_SMART_COACH = 0,
    EXERCISE_SETTING_ITEM_TYPE_GOALS,
    EXERCISE_SETTING_ITEM_TYPE_REMINDER,
    EXERCISE_SETTING_ITEM_TYPE_INTEL_RUN_COMP,
    EXERCISE_SETTING_ITEM_TYPE_WAKEY,
    EXERCISE_MAX_SETTING_ITEM_NUM,
};
typedef uint8_t EXERCISE_SETTING_ITEM_TYPE_T;

enum {
    EXERCISE_REMINDER_ITEM_TYPE_INTERVAL = 0,
    EXERCISE_REMINDER_ITEM_TYPE_HEART_RATE,
    EXERCISE_REMINDER_ITEM_TYPE_TRAINING_EFFECT,
    EXERCISE_REMINDER_ITEM_TYPE_PHYSICAL_STATE,
    EXERCISE_MAX_REMINDER_ITEM_NUM,
};
typedef uint8_t EXERCISE_REMINDER_ITEM_TYPE_T;

enum {
    EXERCISE_VALUE_TYPE_DISTANCE = 0,
    EXERCISE_VALUE_TYPE_TIME,
    EXERCISE_VALUE_TYPE_CALORIE,
};
typedef uint8_t EXERCISE_VALUE_TYPE_T;

enum {
    EXERCISE_HR_RANE_TYPE_EFFICIENT_FAT_BURNING = 0,
    EXERCISE_HR_RANE_TYPE_HEART_LUNG_IMPROVE,
    EXERCISE_HR_RANE_TYPE_RECOVERY_TRAINING,
    EXERCISE_HR_RANE_TYPE_CUSTOM,
};
typedef uint8_t EXERCISE_HR_RANE_TYPE_T;

enum {
    EXERCISE_GOAL_PACE_TYPE_LAST_TIME = 0,
    EXERCISE_GOAL_PACE_TYPE_SINGLE_BEST,
    EXERCISE_GOAL_PACE_TYPE_GENERAL_LEVEL,
    EXERCISE_GOAL_PACE_TYPE_EXPERT_LEVEL,
    EXERCISE_GOAL_PACE_TYPE_CUSTOM,
};
typedef uint8_t EXERCISE_GOAL_PACE_TYPE_T;

typedef struct
{
    uint8_t is_smart_coach_on; // on if 1, off if 0
} __packed exercise_nv_smart_coach_t;
    
typedef struct {
    EXERCISE_VALUE_TYPE_T type;
    uint16_t value;            /* for distance, in kilometers, EXERCISE_GOALS_MIN_DISTANCE_VALUE
                                * to EXERCISE_GOALS_DISTANCE_MARATHON.
                                * for time, in minutes, EXERCISE_GOALS_MIN_TIME_VALUE
                                * to EXERCISE_GOALS_MAX_TIME_VALUE.
                                * for calorie, in kcal, EXERCISE_GOALS_MIN_CAL_VALUE
                                * to EXERCISE_GOALS_MAX_CAL_VALUE */
} __packed exercise_nv_goals_t;

typedef struct {
    EXERCISE_VALUE_TYPE_T type;// distance and time
    uint8_t value;             /* for distance, in kilometers, EXERCISE_GOALS_MIN_TIME_VALUE
                                * to EXERCISE_GOALS_MAX_TIME_VALUE, real value equals to
                                * half of current value.
                                * for time, in minutes, EXERCISE_REMINDER_MIN_TIME_VALUE
                                * to EXERCISE_REMINDER_MAX_TIME_VALUE */
} __packed exercise_nv_interval_reminder_t;

typedef struct {
    uint8_t is_on;              // heart rate reminder, on if 1, off if 0
    EXERCISE_HR_RANE_TYPE_T range_type;
    uint8_t min_value;
    uint8_t max_value;
} __packed exercise_nv_hr_reminder_t;

typedef struct {
    exercise_nv_interval_reminder_t interval;
    exercise_nv_hr_reminder_t hr;
    uint8_t is_training_effect_on;   // on if 1, off if 0
    uint8_t is_physical_state_on;    // on if 1, off if 0
} __packed exercise_nv_reminder_t;

typedef struct {
    uint8_t is_on;              // on if 1, off if 0
    EXERCISE_GOAL_PACE_TYPE_T type;
    uint16_t last_value;        // in sec / km
    uint16_t best_value;        // in sec / km
    uint16_t value;             // in sec / km
} __packed exercise_nv_intel_run_comp_t;

typedef struct
{
    uint8_t is_wakey; // on if 1, off if 0
} __packed exercise_nv_wakey_t;

enum {
    EXERCISE_START_UI_ITEM_TYPE_HEART_RATE = 0,
    EXERCISE_START_UI_ITEM_TYPE_PACE,
    EXERCISE_START_UI_ITEM_TYPE_DISTANCE,
    EXERCISE_START_UI_ITEM_TYPE_DURATION,
    EXERCISE_START_UI_ITEM_TYPE_STEP_NUMBER,
    EXERCISE_START_UI_ITEM_TYPE_STRIDE_FREQUENCY,
    EXERCISE_START_UI_ITEM_TYPE_CALORIE,
    EXERCISE_START_UI_ITEM_TYPE_CUMULATIVELY_CLIMB,
    EXERCISE_START_UI_ITEM_TYPE_HEIGHT,
    EXERCISE_START_UI_ITEM_TYPE_AEROBIC_TRAINING,
    EXERCISE_START_UI_ITEM_TYPE_ANAEROBIC_TRAINING,
    EXERCISE_START_UI_ITEM_TYPE_SPEED,
    EXERCISE_START_UI_ITEM_TYPE_AVERAGE_SPEED,
    EXERCISE_START_UI_ITEM_TYPE_AVERAGE_PACE,
    EXERCISE_START_UI_ITEM_TYPE_RELATIVE_DISTANCE,
};
typedef uint8_t EXERCISE_START_UI_ITEM_TYPE_T;

enum {
    EXERCISE_START_UI_TYPE_4_ITEMS_WITH_TIME = 0,
    EXERCISE_START_UI_TYPE_3_ITEMS_WITH_TIME,
    EXERCISE_START_UI_TYPE_2_ITEMS_WITH_TIME,
    EXERCISE_START_UI_TYPE_1_ITEM_WITH_TIME,
    EXERCISE_START_UI_TYPE_RUNNING_WITH_AI,
    EXERCISE_START_UI_TYPE_TRAINING_EFFECT,
};
typedef uint8_t EXERCISE_START_UI_TYPE_T;

enum {
    EXERCISE_ARC_TYPE_NONE = 0,
    EXERCISE_ARC_TYPE_HR,
    EXERCISE_ARC_TYPE_TRAINING_EFFECT,
};
typedef uint8_t EXERCISE_ARC_TYPE_T;

typedef struct {
    EXERCISE_ARC_TYPE_T arc_type;
    EXERCISE_START_UI_TYPE_T ui_type;
    EXERCISE_START_UI_ITEM_TYPE_T item_type[EXERCISE_MAX_ITEM_NUM_PER_START_UI];
} exercise_start_ui_desc_t;

typedef struct {
    uint8_t ui_count;
    exercise_start_ui_desc_t ui_desc[EXERCISE_MAX_START_UI_NUM];
} exercise_start_desc_t;

typedef struct {
    uint16_t value[EXERCISE_MAX_ROLLER_VALUE_NUM];
    uint16_t custom_min;
    uint16_t custom_max;
    uint16_t custom_step;
    uint16_t custom_default;
} exercise_roller_desc_t;

typedef void (*EXERCISE_GET_GOALS_ROLLER_DESC_CB)(EXERCISE_VALUE_TYPE_T type,
                                                  exercise_roller_desc_t * desc);
typedef void (*EXERCISE_GET_START_DESC_CB)(exercise_start_desc_t * desc);

typedef struct {
    void * img_src;
    lv_color_t img_bg_color;
    uint16_t txt_id;
    bool is_wait_gps; // whether to wait for gps connection in the preparation phase
    EXERCISE_GET_START_DESC_CB start_cb;
    EXERCISE_GET_GOALS_ROLLER_DESC_CB roller_cb;
    uint8_t setting_item_bitmap; // 1 << EXERCISE_SETTING_ITEM_TYPE_XXX
    uint8_t goals_item_bitmap;
    uint8_t reminder_item_bitmap;
    uint8_t interval_reminder_item_bitmap;
} exercise_sport_info_t;

typedef void (*EXERCISE_FUNC_KEY_CB)(void);

/**********************
* GLOBAL PROTOTYPES
**********************/
void exercise_create_event_cb(lv_obj_t * btn, lv_event_t event);
lv_obj_t * exercise_add_list_ui(lv_obj_t * par, uint8_t btn_num);
lv_obj_t * exercise_add_list_btn(exercise_item_t * item, lv_obj_t * list,
                                 exercise_item_info_t * item_info);
lv_obj_t * exercise_add_list_btn_with_long_txt(lv_obj_t * list, char * txt);
void exercise_add_empty_list_btn(lv_obj_t * list);
void exercise_get_goals_txt(exercise_nv_goals_t * nv, char * txt, uint32_t txt_len);
uint32_t exercise_get_nv_offset(uint8_t setting_item_bitmap, EXERCISE_SETTING_ITEM_TYPE_T type);
uint8_t * exercise_get_nv_pointer(uint8_t * nv_data, uint8_t setting_item_bitmap,
                                  EXERCISE_SETTING_ITEM_TYPE_T type);
void exercise_read_nv(EXERCISE_TYPE_T type, uint8_t ** data, uint32_t * data_size);
void exercise_write_nv(EXERCISE_TYPE_T type, uint32_t offset, uint32_t size,
                       void * data, EXERCISE_WRITE_NV_MODE_T mode);
void exercise_com_prepare_destroy(lv_obj_t * activity_obj);

void exercise_get_sport_info(EXERCISE_TYPE_T type, exercise_sport_info_t * info);
void * exercise_get_ext(lv_watch_Activity_Id_t id);
void exercise_del_ui(lv_watch_Activity_Id_t id);
void exercise_int_to_str(uint32_t value, char * str, uint32_t str_len);
int32_t exercise_str_to_int(char * txt);
void exercise_start_recovery_time_anim(exercise_ext_t * ext);

uint32_t exercise_nv_init(uint8_t setting_item_bitmap, uint8_t ** data);

void exercise_main_sport_cb(lv_obj_t * btn, lv_event_t event);
void exercise_main_sport_setting_cb(lv_obj_t * btn, lv_event_t event);

bool exercise_sport_home_key_handle(void);
bool exercise_sport_back_key_handle(void);

// outdoor running
void exercise_outdoor_running_get_sport_info(exercise_sport_info_t * info);

// outdoor cycling
void exercise_outdoor_cycling_get_sport_info(exercise_sport_info_t * info);

// walking
void exercise_walking_get_sport_info(exercise_sport_info_t * info);

// free training
void exercise_free_training_get_sport_info(exercise_sport_info_t * info);

#endif /*USE_LV_WATCH_EXERCISE*/

#ifdef __cplusplus
} /* extern "C" */
#endif

#endif /*EXERCISE_H*/
